package cn.tedu.charging.order.amqp;

import cn.tedu.charging.common.constant.AmqpComponentConst;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.order.service.ConsumerService;
import com.alibaba.fastjson2.JSON;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 这个消费类
 * 定位 是amqp消息队列的消费入口
 * 业务不在这里实现,只处理消息解析和手动确认
 */
@Component
@Slf4j
public class AmqpConsumer {
    @Autowired
    private ConsumerService consumerService;
    @Autowired
    private RedisTemplate redisTemplate;
    //监听延迟队列
    @RabbitListener(queues= AmqpComponentConst.DELAY_BILL_DL_QUEUE)
    public void consumeDelayBill(String body, Message message, Channel channel){

        DelayCheckMessage msg = JSON.parseObject(body, DelayCheckMessage.class);
        //1.先抢锁 key 锁的key值 锁住当前同一个订单
        String orderLock="charging:order:consume:"+msg.getOrderNo()+".lock";
        //set orderLock "" NX EX 5 抢锁的同时 设置超时5秒钟
        Boolean haveKey = redisTemplate.opsForValue().setIfAbsent(orderLock, "", 5, TimeUnit.SECONDS);
        //判断,只有抢到锁的线程,才能有资格执行业务
        try{
        if (haveKey){
            //2.執行核心業務
            consumerService.handleDelayCheck(msg);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            }
        }catch (Exception e){
            log.info("消息确认失败",e);
        }finally{
            //3.手動釋放鎖
            //无论业务执行成功还是失败,还是异常,都要保证 释放锁的有效性
            redisTemplate.delete(orderLock);
        }
    }
}
